package com.hn.zhijian.base.common.converter;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.alibaba.fastjson.support.config.FastJsonConfig;
import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter;
import com.hn.zhijian.base.common.ApplicationBeanUtil;
import com.hn.zhijian.base.common.ConfigurationYmlProperty;
import com.hn.zhijian.base.common.Path;
import com.hn.zhijian.base.common.StatusCode;
import com.hn.zhijian.base.model.response.Response;
import com.hn.zhijian.utils.DateUtils;
import com.hn.zhijian.utils.Utils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpOutputMessage;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageNotWritableException;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.List;
import java.util.Map;

/**
 * @author carl
 * @文件名 :增强write方法 Object对象包含@Path注解的属性
 * @描述 :自定义统一返回格式
 */
@Slf4j
public class ApplicationJsonHttpMessageConverter extends FastJsonHttpMessageConverter {

    private ConfigurationYmlProperty configurationYmlProperty;

    public ApplicationJsonHttpMessageConverter(){
        configurationYmlProperty = ApplicationBeanUtil.getBean(ConfigurationYmlProperty.class);
    }

    public static FastJsonConfig getCustomizeFastJsonConfig(){
        FastJsonConfig config = new FastJsonConfig();
        config.setSerializerFeatures(
                // 保留 Map 空的字段
                SerializerFeature.WriteMapNullValue,
                // 将 String 类型的 null 转成""
                SerializerFeature.WriteNullStringAsEmpty,
                // 将 Number 类型的 null 转成 0
                SerializerFeature.WriteNullNumberAsZero,
                // 将 List 类型的 null 转成 []
                SerializerFeature.WriteNullListAsEmpty,
                // 将 Boolean 类型的 null 转成 false
                SerializerFeature.WriteNullBooleanAsFalse,
                // 避免循环引用
                SerializerFeature.DisableCircularReferenceDetect);
        //转换日期格式
        config.setDateFormat(DateUtils.YYYY_MM_DD_HH_MM_SS);
        return config;
    }


    @Override
    public void write(Object o, Type type, MediaType contentType, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException {
        try {
            readyWrite(o);
        } catch (Exception e) {
//            logger.info("重写json字符失败");
        }
        super.write(o, type, contentType, outputMessage);
    }

    private void readyWrite(Object o) throws Exception {
        if (o instanceof Response) {
            Response response = (Response) o;
            //只解析code等于两百的
            if (response.getCode() == StatusCode.OK.getCode()) {
                if (Utils.notEmpty(response.getBody())) {
                    if (response.getBody() instanceof List<?>) {
                        //list
                        writeList((List<?>) response.getBody());
                    } else if (response.getBody() instanceof Map<?, ?>) {
                        //map
                        writeMap((Map<?, ?>) response.getBody());
                    } else {
                        //普通对象
                        if(!(o instanceof String)) {
                            write(response.getBody());
                        }
                    }
                }
            }
        }else {
            if(o instanceof  List<?>){
                writeList((List<?>) o);
            }else if(o instanceof  Map<?,?>){
                writeMap((Map<?, ?>) o);
            }else{
                //不能等于String
                if(!(o instanceof String)){
                    write(o);
                }
            }
        }
    }

    /**
     * 写入list
     *
     * @param list
     * @return
     * @throws Exception
     */
    private Object writeList(List<?> list) throws Exception {


        if (Utils.notEmpty(list)) {
            for (Object o : list) {
                write(o);
            }
        }
        return list;
    }

    /**
     * 写入map
     * @param map
     * @return
     * @throws Exception
     */
    private Object writeMap(Map<?, ?> map) throws Exception {
        for (Map.Entry<?, ?> m : map.entrySet()) {
            Object value = m.getValue();
            readyWrite(value);
        }
        return map;
    }


    /**
     * 写入Object
     *
     * @param o
     * @return
     * @throws Exception
     */
    private Object write(Object o) throws Exception {
        Class<?> objectClass = o.getClass();
        //获取子类的成员属性
        Field[] fields = objectClass.getDeclaredFields();
//
        if (Utils.notEmpty(fields)) {
            for (Field field : fields) {

                field.setAccessible(true);

                Path path = field.getAnnotation(Path.class);
                //set方法
                Method setMethod = getMethod(objectClass.getMethods(), field.getName(), MethodType.METHOD_SET.getValue());

                //get方法
                Method getMethod = getMethod(objectClass.getMethods(), field.getName(), MethodType.METHOD_GET.getValue());

                Object value = getMethod.invoke(o);

                if (Utils.notEmpty(path)) {
                    setMethod.invoke(o, getFileUrl(path, (String)value));
                    continue;
                }
                //获取类型
                Class<?> type = field.getType();
                //如果不是基础类型就解析
                if (!type.isPrimitive() && !type.isAssignableFrom(String.class)) {
                    Object o1 = new Object();
                    if (type.isAssignableFrom(List.class)) {
                        //如果类型是一个List
                        o1 = writeList((List<?>) value);
                    } else if (type.isAssignableFrom(Map.class)) {
                        //如果类型是一个Map
                        o1 = writeMap((Map<?, ?>) value);
                    } else {
                        //对象
                        o1 = write(value);
                    }
                     setMethod.invoke(o, o1);
                }
            }
        }
        return o;
    }


    /**
     * 组装文件全路径
     * @param path
     * @param fileUrl
     * @return
     */
    private String getFileUrl(Path path, String fileUrl) {

        String url = path.url();

        if(Utils.isEmpty(url)){
            url = configurationYmlProperty.getShowFilePathPrefix();
        }

        if(path.pathStyle().equals(PathStyle.PATH_STYLE_FRONT)){
            fileUrl = url+fileUrl;
        }else{
            fileUrl +=  url;
        }

        return fileUrl;
    }


    /**
     * @param methods 当前类所有方法
     * @param name    属性名
     * @param type    set get
     * @return
     */
    private Method getMethod(Method[] methods, String name, String type) {
        if (Utils.notEmpty(methods)) {
            for (Method m : methods) {
                if (m.getName().toLowerCase().equals((type + name).toLowerCase())) {
                    return m;
                }
            }
        }
        return null;
    }
}
